package 代码随想录_动态规划.子序列问题.不连续;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author zx
 * @create 2022-06-05 9:12
 * 1.确定dp数组（dp table）以及下标的含义
 *  dp[i]表示i之前包括i的最长上升子序列。
 * 2.确定递推公式
 *  位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。
 *  所以：if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
 *  注意这里不是要dp[i] 与 dp[j] + 1进行比较，而是我们要取dp[j] + 1的最大值。
 * 3.dp数组如何初始化
 *  每一个i，对应的dp[i]（即最长上升子序列）起始大小至少都是是1.
 * 4.确定遍历顺序
 *  dp[i] 是有0到i-1各个位置的最长升序子序列 推导而来，那么遍历i一定是从前向后遍历。
 * 5.举例推导dp数组
 *
 */
public class 最长递增子序列_300 {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        for(int i = 0;i < dp.length;i++){
            dp[i] = 1;
        }
        int res = 1;
        for(int i = 1;i < nums.length;i++){
            for(int j = 0;j < i;j++){
                //注意这里不是要dp[i]与dp[j] + 1进行比较,而是要取dp[j] + 1的最大值。
                if(nums[i] > nums[j]){
                    dp[i] = Math.max(dp[i],dp[j] + 1);
                }
            }
            res = Math.max(res,dp[i]);//取长的子序列
        }
        return res;
    }

    /**
     * 题目变种,需要返回最长递增子序列而不是其长度,2025滴滴三面面试真题
     */
    public static List<Integer> findArr(int[] arr){
        int[] dp = new int[arr.length];
        for(int i = 0;i < dp.length;i++) dp[i] = 1;
        int res = 0;
        int right = 0;
        for(int i = 0;i < arr.length;i++){
            for(int j = 0;j < i;j++){
                if(arr[j] < arr[i]){
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            if(dp[i] > res){
                res = Math.max(res, dp[i]);
                right = i;
            }
        }
        // 用一个right变量存储最长递增子序列的右边界，知道了右边界和最长递增子序列的长度
        // 从右边界向左找, 长度>=0,长度--,用一个List收集递减的节点
        int prev = arr[right];
        List<Integer> list = new ArrayList<>();
        list.add(arr[right]);
        for(int i = right - 1;i >= 0 && res >= 0;i--){
            if(prev > arr[i]){
                list.add(arr[i]);
                prev = arr[i];
                res--;
            }
        }
        // 由于是从后往前收集，需要反转列表以得到正确顺序
        Collections.reverse(list);
        return list;
    }
}
